<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
		<title>工匠租-租赁合同签署</title>
		<style>
			* {
				margin: 0;
				padding: 0;
				box-sizing: border-box;
				font-family: sans-serif;
			}

			html,
			body {
				width: 100%;
				background-color: #fff;
			}

			.footer_btn {
				position: fixed;
				bottom: 0px;
				left: 0;
				right: 0;
				z-index: 99;
				display: flex;
				justify-content: center;
				padding-bottom: 10px;
				padding-top: 10px;
			}

			#signBtn {
				width: 90%;
				background-color: #e87722;
				color: #fff;
				font-size: 14px;
				height: 35px;
				border-radius: 50px;
				border: 0;
			}

			.signature-wrapper {
				width: 100%;
				border: 1px solid #eee;
				border-radius: 8px;
				overflow: hidden;
				position: fixed;
				bottom: 0;
				left: 0;
				right: 0;
				z-index: 999;
				/* visibility: hidden; */
				transform: translateY(400px);
				transition: all 0.3s linear;
			}

			.signature-wrapper.show {
				transform: translateY(0px);
			}

			/* 签名画布容器 */
			.signature-canvas-container {
				width: 100%;
				height: 300px;
				/* 可自定义高度 */
				background: #fff;
				position: relative;
			}

			#signatureCanvas {
				width: 100%;
				height: 100%;
				cursor: crosshair;
			}

			/* 无签名时的提示 */
			.empty-tip {
				position: absolute;
				top: 50%;
				left: 50%;
				transform: translate(-50%, -50%);
				color: #999;
				font-size: 14px;
				pointer-events: none;
				/* 不影响触摸 */
			}

			/* 功能按钮区 */
			.signature-actions {
				display: flex;
				gap: 10px;
				padding: 15px;
				background: #f5f5f5;
				border-top: 1px solid #eee;
			}

			.signature-btn {
				padding: 8px 16px;
				border: none;
				border-radius: 4px;
				cursor: pointer;
				font-size: 14px;
				flex: 1;
			}

			.btn-clear {
				background: #fef2f2;
				color: #dc2626;
			}

			.btn-save {
				background: #e0f2fe;
				color: #0284c7;
			}

			#previewImg {
				width: 100%;
				border: 1px solid #eee;
				border-radius: 4px;
				padding: 10px;
			}
		</style>
	</head>
	<body>
		<div id="readfile" style="padding:0 10px;"></div>
		<div class="signature-wrapper">
			<div class="signature-canvas-container">
				<canvas id="signatureCanvas"></canvas>
				<div class="empty-tip" id="emptyTip">请在画布上签名</div>
			</div>
			<div class="signature-actions">
				<button class="signature-btn btn-reset" id="btnCanle">取消签名</button>
				<button class="signature-btn btn-clear" id="btnClear">清空签名</button>
				<button class="signature-btn btn-save" id="btnSave">确认签名</button>
			</div>
		</div>
		<!-- <img id="previewImg" alt="签名预览"> -->
		<div style="height: 60px;"></div>
		<div class="footer_btn" style="background-color: #fff;">
			<button type="button" id="signBtn">签署文件</button>
		</div>
		<script type="text/javascript" src="/static/js/uni.webview.1.5.6.js"></script>
		<script type="text/javascript">
			var userAgent = navigator.userAgent;
			if (userAgent.indexOf('AlipayClient') > -1) {
				document.writeln('<script src="https://appx/web-view.min.js"' + '>' + '<' + '/' + 'script>');
			} else if (/miniProgram/i.test(userAgent) && /micromessenger/i.test(userAgent)) {
				document.write('<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"><\/script>');
			}
			document.addEventListener('UniAppJSBridgeReady', () => {
				const params = getUrlParams();
				const apiUrl = decodeURIComponent(params.url)

				function loadFile() {
					const script = document.createElement('script');
					script.src = `/static/js/docx.min.js`;
					script.onload = () => {
						setTimeout(() => {
							renderFile()
						}, 500)
						// 脚本加载完成后，可直接使用 my 对象
					};
					script.onerror = (err) => {
						console.error('docx.min.js 引入失败：', err);
					};
					document.head.appendChild(script);
				}
				loadFile();

				async function renderFile() {
					const response = await fetch(
						`${apiUrl}/index.php/api/order/renderContract?order_id=${params.sn}&redirect_url=/pages/h5/h5`, {
							method: 'GET',
							headers: {
								'Content-Type': 'application/json',
								'ba-user-token': params.s
							}
						});
					const res = await response.text();
					document.getElementById('readfile').innerHTML = res
					// if (res.code == 1) {
					// 	const url = res.data.sign_url
					// 	Docx.docx2HTML(url).then(docx => {
					// 		docx.toHTML(document.getElementById('readfile'))
					// 	});
					// }
				}

				function getUrlParams(url = window.location.href) {
					const params = {};
					// 1. 提取查询字符串（? 后面的部分）
					const queryString = url.split('?')[1];
					if (!queryString) return params; // 无参数时返回空对象

					// 2. 分割参数（& 分隔多个参数）
					const paramArr = queryString.split('&');

					// 3. 遍历解析每个参数（= 分隔键和值）
					paramArr.forEach(item => {
						// 处理有值的参数（key=value）和无值的参数（key）
						const [key, value = true] = item.split('=');
						// 解码特殊字符（如中文、空格、& 等）
						const decodeKey = decodeURIComponent(key);
						const decodeValue = typeof value === 'string' ? decodeURIComponent(value) : value;

						// 处理重复参数（如 ?name=张三&name=李四，返回数组）
						if (params[decodeKey]) {
							params[decodeKey] = Array.isArray(params[decodeKey]) ? [...params[decodeKey], decodeValue] : [params[
								decodeKey], decodeValue];
						} else {
							params[decodeKey] = decodeValue;
						}
					});

					return params;
				}

				class Signature {
					constructor(options = {}) {
						// 默认配置
						this.config = {
							canvasId: 'signatureCanvas', // Canvas 元素ID
							lineWidth: 3, // 线条宽度
							strokeColor: '#000', // 线条颜色
							bgColor: '#fff', // 画布背景色
							lineCap: 'round', // 线条端点样式（round/square/butt）
							lineJoin: 'round', // 线条交点样式（round/bevel/miter）
							isClearEmptyTip: true // 开始签名后隐藏空提示
						};

						// 合并用户配置
						Object.assign(this.config, options);

						// 核心属性
						this.canvas = document.getElementById(this.config.canvasId);
						this.ctx = this.canvas.getContext('2d');
						this.isDrawing = false; // 是否正在绘制
						this.lastPos = {
							x: 0,
							y: 0
						}; // 上一个点坐标
						this.hasDrawn = false; // 是否有签名轨迹（用于判断是否为空）
						this.emptyTip = document.getElementById('emptyTip');
						this.params = getUrlParams();
						this.api = decodeURIComponent(this.params.url)
						this.saveLoading = false
						// 初始化
						this.init();
					}

					/**
					 * 初始化画布（解决模糊问题 + 适配屏幕）
					 */
					init() {
						if (!this.canvas) throw new Error('未找到 Canvas 元素');

						// 适配高清屏：获取设备像素比
						this.dpr = window.devicePixelRatio || 1;

						// 设置 Canvas 实际宽高（避免模糊）
						const container = this.canvas.parentElement;
						const width = container.clientWidth;
						const height = container.clientHeight;

						// 物理像素宽高 = 逻辑宽高 * 设备像素比
						this.canvas.width = width * this.dpr;
						this.canvas.height = height * this.dpr;

						// 缩放绘图上下文
						this.ctx.scale(this.dpr, this.dpr);

						// 配置绘图样式
						this.ctx.lineWidth = this.config.lineWidth;
						this.ctx.strokeColor = this.config.strokeColor;
						this.ctx.lineCap = this.config.lineCap;
						this.ctx.lineJoin = this.config.lineJoin;

						// 绑定事件
						this.bindEvents();
					}

					/**
					 * 绑定触摸/鼠标事件
					 */
					bindEvents() {
						// 鼠标事件（PC端）
						this.canvas.addEventListener('mousedown', (e) => this.startDraw(e));
						this.canvas.addEventListener('mousemove', (e) => this.drawing(e));
						this.canvas.addEventListener('mouseup', () => this.endDraw());
						this.canvas.addEventListener('mouseout', () => this.endDraw());

						// 触摸事件（移动端）
						this.canvas.addEventListener('touchstart', (e) => {
							e.preventDefault(); // 阻止页面滚动
							this.startDraw(e.touches[0]);
						});
						this.canvas.addEventListener('touchmove', (e) => {
							e.preventDefault();
							this.drawing(e.touches[0]);
						});
						this.canvas.addEventListener('touchend', () => this.endDraw());
						this.canvas.addEventListener('touchcancel', () => this.endDraw());

						// 按钮事件（外部绑定，也可内部绑定）
						document.getElementById('btnClear').addEventListener('click', () => this.clear());
						document.getElementById('btnSave').addEventListener('click', () => this.save());

						document.querySelector('#signBtn').addEventListener('click', () => {
							document.querySelector('.signature-wrapper').classList.add('show')
						})
						document.querySelector('#btnCanle').addEventListener('click', () => {
							document.querySelector('.signature-wrapper').classList.remove('show')
							this.clear()
						})
					}

					/**
					 * 开始绘制（触摸/鼠标按下）
					 */
					startDraw(e) {
						this.isDrawing = true;

						// 获取相对于 Canvas 的坐标
						const pos = this.getRelativePos(e);
						this.lastPos = pos;

						// 隐藏空提示
						if (this.config.isClearEmptyTip) {
							this.emptyTip.style.display = 'none';
						}

						// 开始路径
						this.ctx.beginPath();
						this.ctx.moveTo(pos.x, pos.y);
					}

					/**
					 * 绘制中（触摸/鼠标移动）
					 */
					drawing(e) {
						if (!this.isDrawing) return;

						const currentPos = this.getRelativePos(e);

						// 绘制线条
						this.ctx.lineTo(currentPos.x, currentPos.y);
						this.ctx.stroke();

						// 更新上一个点坐标
						this.lastPos = currentPos;

						// 标记已绘制
						this.hasDrawn = true;
					}

					/**
					 * 结束绘制（触摸/鼠标松开）
					 */
					endDraw() {
						this.isDrawing = false;
						this.ctx.closePath();
					}

					/**
					 * 获取触摸点相对于 Canvas 的坐标
					 */
					getRelativePos(e) {
						const rect = this.canvas.getBoundingClientRect();
						return {
							x: e.clientX - rect.left,
							y: e.clientY - rect.top
						};
					}

					/**
					 * 清空签名
					 */
					clear() {
						// 清空整个画布
						this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
						// 重置状态
						this.hasDrawn = false;
						// 显示空提示
						this.emptyTip.style.display = 'block';
					}

					/**
					 * 保存签名（返回 Base64/Blob）
					 * @param {String} type - 保存类型：base64/blob
					 * @returns {String/Blob} 签名数据
					 */
					save(type = 'blob') {
						if (!this.hasDrawn) {
							alert('请先签名再保存！');
							return;
						}
						// const previewImg = document.getElementById('previewImg');
						if (type === 'base64') {
							// 保存为 Base64（默认，可直接用于 img 标签或上传后端）
							const base64 = this.canvas.toDataURL('image/png');
							console.log('签名 Base64：', base64);
							return base64;
						} else if (type === 'blob') {
							document.querySelector('#btnSave').innerText = '签署中'
							if (this.saveLoading) return;
							this.saveLoading = true
							this.uploadByBlobWithFetch().then(res => {
								if (res.code == 1) {
									const url = `${this.api}${res.data.file.url}`
									this.signDocument(url)
								} else {
									this.saveLoading = false
								}
							})
							// 保存为 Blob（适合大文件上传，体积更小）
							// this.canvas.toBlob((blob) => {
							// 	const blobUrl = URL.createObjectURL(blob);
							// 	previewImg.src = blobUrl;
							// 	this.uploadByBlobWithFetch()
							// 	console.log('签名 Blob：', blobUrl);
							// }, 'image/png');
						}
					}
					async signDocument(url) {
						try {
							const submitData = {
								order_id: this.params.sn,
								sign_img_url: url
							}
							const response = await fetch(`${this.api}/index.php/api/order/signByImage`, {
								method: 'POST',
								headers: {
									'Content-Type': 'application/json',
									'ba-user-token': this.params.s
								},
								body: JSON.stringify(submitData), // 转换为JSON字符串
								timeout: 10000 // 超时时间：10秒（部分浏览器不支持fetch timeout，需额外处理）
							});
							const res = await response.json();
							this.saveLoading = false
							if (res.code == 1) {
								const message = {
									type: 'sign',
									sn: this.params.sn
								}
								if (typeof wx !== 'undefined' && wx.miniProgram) {
									wx.miniProgram.redirectTo({
										url: `/pages/order/signSuccess?sn=${this.params.sn}`, // 小程序页面路径+参数
										success: () => {
											console.log('H5 跳转小程序成功');
										},
										fail: (err) => {
											console.error('H5 跳转小程序失败：', err);
											alert('跳转失败，请重试');
										}
									});
								} else if (userAgent.indexOf('AlipayClient') > -1) {
									my.postMessage(message)
								} else {
									uni.redirectTo({
										url: `/pages/order/signSuccess?sn=${this.params.sn}`
									})
								}
							} else {
								alert('签署失败')
							}
						} catch (error) {
							this.saveLoading = false
							console.log(error)
						}
					}
					/**
					 * 【推荐】fetch + Blob 上传（体积小、传输快）
					 * @param {String} blobUrl - 图片地址
					 * @returns {Promise} 上传结果
					 */
					async uploadByBlobWithFetch() {
						if (!this.hasDrawn) {
							alert('请先签名再上传！');
							return Promise.reject('签名为空');
						}

						try {
							const blob = await new Promise((resolve) => {
								this.canvas.toBlob(resolve, 'image/png'); // 转为 PNG 格式 Blob
							});
							const formData = new FormData();
							formData.append('file', blob, `signature_${Date.now()}.png`);
							// 3. fetch 发送请求
							const response = await fetch(`${this.api}/index.php/api/ajax/upload`, {
								method: 'POST',
								headers: {
									'ba-user-token': this.params.s
								},
								body: formData
							});
							const result = await response.json();
							console.log('Blob 上传成功：', result);
							return result;
						} catch (err) {
							console.error('Blob 上传失败：', err);
							return Promise.reject(err);
						}
					}
				}

				// 初始化签名组件（可传入自定义配置）
				window.onload = () => {
					if (params.status == 2) {
						document.querySelector('.footer_btn').style.display = 'none'
					}
					new Signature({
						lineWidth: 4, // 自定义线条宽度
						strokeColor: '#000000' // 自定义线条颜色
					});
				};
			})
		</script>
	</body>
</html>